const PENDING = "pending";
const REJECTED = "rejected";
const RESOLVED = "resolved";
const resolvePromise = (jjpromise2, result, resolve, reject) => {
  if (jjpromise2 === result) {
    reject(new TypeError("promise can not return oneself 不能返回自己"));
  }
  if (
    (typeof result === "object" && result !== null) ||
    typeof result === "function"
  ) {
    let called = false; //别人的promise可能成功失败都一起调用,用called来锁住,下面判断called可以让成功和失败只能调一次
    try {
      const then = result.then;
      if (typeof then === "function") {
        then.call(
          result,
          (r) => {
            if (called) {
              return;
            }
            called = true;
            resolvePromise(jjpromise2, r, resolve, reject);
          },
          (y) => {
            if (called) {
              return;
            }
            called = true;
            resolvePromise(jjpromise2, y, resolve, reject);
          }
        );
      } else {
        resolve(result);
      }
    } catch (e) {
      if (called) {
        return;
      }
      called = true;
      reject(e);
    }
  } else {
    resolve(result);
  }
};
class JJpromise {
  constructor(executor) {
    this.status = PENDING; //默认是pending等待
    this.value = undefined; // 成功的值
    this.reason = undefined; // 失败的原因
    this.onResolveCallback = [];
    this.onRejectCallback = [];
    const resolve = (value) => {
      if (this.status === PENDING) {
        this.status = RESOLVED;
        this.value = value;
        this.onResolveCallback.map((fn) => fn());
      }
    };
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.reason = reason;
        this.status = REJECTED;
        this.onRejectCallback.map((fn) => fn());
      }
    };
    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onResolved, onRejected) {
    onResolved = typeof onResolved === "function" ? onResolved : (data) => data;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (err) => {
            throw err;
          };
    const jjpromise2 = new JJpromise((resolve, reject) => {
      if (this.status === RESOLVED) {
        setTimeout(() => {
          try {
            const result = onResolved(this.value);
            resolvePromise(jjpromise2, result, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            const err = onRejected(this.reason);
            resolvePromise(jjpromise2, err, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      //异步的时候
      if (this.status === PENDING) {
        this.onResolveCallback.push(() => {
          setTimeout(() => {
            try {
              const result = onResolved(this.value);
              resolvePromise(jjpromise2, result, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.onRejectCallback.push(() => {
          setTimeout(() => {
            try {
              const err = onRejected(this.reason);
              resolvePromise(jjpromise2, err, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      }
    });
    return jjpromise2;
  }
  catch(onRejected) {
    return this.then(undefined, onRejected);
  }
  finally(cb) {
    return this.then(
      (res) => {
        cb();
        return res;
      },
      (err) => {
        cb();
        throw err;
      }
    );
  }
  static resolve(value) {
    return new JJpromise((resolve) => resolve(value));
  }
  static reject(value) {
    return new JJpromise((resolve, reject) => reject(value));
  }

  static all(values) {
    return new JJpromise((resolve, reject) => {
      const arr = [];
      let flag = 0;
      const processData = (key, value) => {
        flag++;
        arr[key] = value;
        if (flag == values.length) {
          resolve(arr);
        }
      };
      values.map((item, index) => {
        if (
          (typeof item === "object" && item !== null) ||
          typeof item === "function"
        ) {
          item.then((data) => {
            processData(index, data);
          }, reject);
        } else {
          processData(index, item);
        }
      });
    });
  }
  static race(values) {
    return new JJpromise((resolve, reject) => {
      values.map((item) => {
        if (
          (typeof item === "object" && item !== null) ||
          typeof item === "function"
        ) {
          item.then(resolve, reject);
        } else {
          resolve(item);
        }
      });
    });
  }
}

module.exports = JJpromise;
